package com.vogue.supplymall.order.domain.biz.impl;

import com.vogue.supplymall.account.domain.model.BaseCode;
import com.vogue.supplymall.account.domain.service.BaseCodeService;
import com.vogue.supplymall.common.domain.dto.SearchPrepayInfo;
import com.vogue.supplymall.common.domain.dto.UpdatePrepay;
import com.vogue.supplymall.common.exception.DataNotFindException;
import com.vogue.supplymall.order.domain.biz.PrepaySearchBiz;
import com.vogue.supplymall.order.domain.model.Account;
import com.vogue.supplymall.order.domain.model.AccountPrepay;
import com.vogue.supplymall.order.domain.model.SupplierConsumer;
import com.vogue.supplymall.order.domain.service.AccountPrepayService;
import com.vogue.supplymall.order.domain.service.AccountService;
import com.vogue.supplymall.order.domain.service.SupplierConsumerService;
import com.vogue.supplymall.order.exception.SearchPrepayException;
import com.vogue.supplymall.shop.domain.model.Shop;
import com.vogue.supplymall.shop.domain.service.ShopService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * The type Prepay search biz.
 *
 * @author zhangliang
 * Create in 2018-08-01
 */
@Service("prepaySearchBiz")
public class PrepaySearchBizImpl implements PrepaySearchBiz {

    public static final Logger LOGGER_PREPAYSEARCHBIZIMPL = LoggerFactory.getLogger(PrepaySearchBizImpl.class);
    @Resource
    private AccountPrepayService accountPrepayService;
    @Resource
    private BaseCodeService baseCodeService;
    @Resource
    private SupplierConsumerService supplierConsumerService;
    @Resource
    private ShopService shopService;
    @Resource
    private AccountService accountService;

    @Override
    public List<Map<String, Object>> searchPrepayForOrgan(SearchPrepayInfo searchPrepayInfo) {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ").append(" mo.entname orgname, ").
                append(" ap.sellsyscodeid, ").
                append(" SUM(ap.balance) balance ").
                append(" FROM ").
                append(" account a ").
                append("INNER JOIN account_prepay ap ON (a.id = ap.accountid) ").
                append("INNER JOIN shop mo ON ( ").
                append(" ap.sellorganid = mo.organid) ").
                append("WHERE ").
                append(" ap.buysyscodeid = #{syscodeid} ");
        if (StringUtils.isNotEmpty(searchPrepayInfo.getKeyword())) {
            sql.append(" AND mo.entname like CONCAT('%',#{keyword},'%') ");
        }
        sql.append(" GROUP BY ").append(" sellsyscodeid ").append(" LIMIT #{start},#{end} ");

        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", searchPrepayInfo.getSyscodeid());
        para.put("start", searchPrepayInfo.getStart());
        para.put("end", searchPrepayInfo.getLength());
        para.put("keyword", searchPrepayInfo.getKeyword());
        List<Map<String, Object>> data = accountPrepayService.query0(sql.toString(), para);
        for (Map<String, Object> datum : data) {
            BaseCode baseCode = baseCodeService.get(new Long(datum.get("sellsyscodeid").toString()));
            if (null != baseCode) {
                datum.put("syscode", baseCode.getSyscode());
            }
        }
        return data;
    }

    @Override
    public Map<String, Object> searchPrepayForShop(SearchPrepayInfo searchPrepayInfo) {
        String sql = "SELECT "
                + " mo.name orgname, "
                + " ap.sellsyscodeid, "
                + " ap.sellorganid, "
                + " ap.balance "
                + " FROM "
                + " account_prepay ap "
                + " INNER JOIN shop mo ON ( "
                + " ap.sellsyscodeid = mo.syscodeid "
                + " AND ap.sellorganid = mo.organid) "
                + " WHERE "
                + " ap.buysyscodeid = #{syscodeid} "
                + "and ap.buyorganid = #{buyorganid} "
                + " and ap.sellsyscodeid = #{sellsyscodeid} "
                + " GROUP BY "
                + " sellorganid "
                + " LIMIT #{start},#{end} ";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", searchPrepayInfo.getSyscodeid());
        para.put("buyorganid", searchPrepayInfo.getOrganid());
        para.put("sellsyscodeid", searchPrepayInfo.getSellsyscodeid());
        para.put("start", searchPrepayInfo.getStart());
        para.put("end", searchPrepayInfo.getLength());
        List<Map<String, Object>> lists = accountPrepayService.query0(sql, para);
        // 计算门店总余额
        Function<List<Map<String, Object>>, BigDecimal> calcTotal = (list) -> list
                .stream()
                .map((Map<String, Object> map) -> new BigDecimal(map.get("balance").toString()))
                .reduce(BigDecimal.ZERO, (acc, x) -> acc.add(x));
        Map<String, Object> data = new HashMap<>();
        data.put("list", lists);
        data.put("shopTotal", BigDecimal.ZERO);
        data.put("total", BigDecimal.ZERO);
        if (searchPrepayInfo.isAdmin()) {
            data.put("shopTotal", calcTotal.apply(lists));
            List<Map<String, Object>> organTotal = searchPrepayForOrgan(searchPrepayInfo);
            data.put("total", calcTotal.apply(organTotal));
        } else {
            data.put("total", calcTotal.apply(lists));
        }
        return data;
    }

    @Override
    public List<Map<String, Object>> searchPrepayForShopDetail(SearchPrepayInfo searchPrepayInfo) {
        String sql = " SELECT "
                + " case when apd.type = 1 or apd.type = 3 then apd.orderid when apd.type = 4 then apd.refundid else 0 end as orderid,"
                + " case when apd.type = 1 or apd.type = 3 then o.ordernumber when apd.type = 4 then ro.refundnumber else '' end as ordernumber,"
                + " apd.createdate, "
                + " apd.type, "
                + " apd.amount "
                + " FROM "
                + " account_prepay_detail apd "
                + " LEFT JOIN `order` o on (apd.orderid = o.id) "
                + " LEFT JOIN `refund_order` ro on (apd.refundid = ro.id) "
                + " WHERE "
                + " apd.buysyscodeid = #{syscodeid} "
                + " and apd.buyorganid = #{organid} "
                + " AND apd.sellsyscodeid = #{sellsyscodeid} "
                + " AND apd.sellorganid = #{sellorganid} order by apd.createdate desc "
                + "LIMIT #{start},#{end}";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", searchPrepayInfo.getSyscodeid());
        para.put("sellsyscodeid", searchPrepayInfo.getSellsyscodeid());
        para.put("organid", searchPrepayInfo.getOrganid());
        para.put("sellorganid", searchPrepayInfo.getSellorganid());
        para.put("start", searchPrepayInfo.getStart());
        para.put("end", searchPrepayInfo.getLength());
        return accountPrepayService.query0(sql, para);
    }

    @Override
    @Transactional
    public Map<String, String> searchPrepayBalance(SearchPrepayInfo searchPrepayInfo) {
        String sql = "SELECT ap.balance FROM account a INNER JOIN account_prepay ap ON (a.id = ap.accountid) "
                + "WHERE ap.buysyscodeid = #{syscodeid} AND ap.buyorganid = #{organid} and sellorganid = #{sellorganid} ";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", searchPrepayInfo.getSyscodeid());
        para.put("organid", searchPrepayInfo.getOrganid());
        para.put("sellsyscodeid", searchPrepayInfo.getSellsyscodeid());
        para.put("sellorganid", searchPrepayInfo.getSellorganid());
        List<Map<String, Object>> data = accountPrepayService.query0(sql, para);
        Map<String, String> result = new HashMap<>();
        result.put("balance", "0");
        // paymode 0:不限 1:线上 2:线下 3:不能支付
        result.put("paymode", "3");
        if (data.size() > 0) {
            result.put("balance", data.get(0).get("balance").toString());
        }
        // 查看店铺的mcid是否存在
        String shopSql = " syscodeid = #{sellsyscodeid} and organid = #{sellorganid}";
        Shop shop = shopService.selectOneByWhr0(shopSql, para);

        if (null != shop) {
            // 查看客户关系
            String supplierSql = " buysyscodeid = #{syscodeid} and buyorganid = #{organid} and sellsyscodeid = #{sellsyscodeid}";
            SupplierConsumer supplierData = supplierConsumerService.selectOneByWhr0(supplierSql, para);

            if ("0".equals(shop.getMcid()) || StringUtils.isEmpty(shop.getMcid())) {
                if (null == supplierData) {
                    if (1 != shop.getPaymode()) {
                        result.put("paymode", "2");
                    }
                } else {
                    if (1 != supplierData.getPaymode()) {
                        result.put("paymode", "2");
                    }
                }
            } else {
                // 使用店铺默认的支付限制方式
                result.put("paymode", shop.getPaymode().toString());
                if (null != supplierData) {
                    result.put("paymode", supplierData.getPaymode().toString());
                }
            }
        }
        return result;
    }

    @Override
    public Boolean existAccountPrepay(SearchPrepayInfo searchPrepayInfo) {
        Map<String, Long> result = new HashMap<>();
        result.put("syscodeid", searchPrepayInfo.getSyscodeid());
        result.put("organid", searchPrepayInfo.getOrganid());
        result.put("sellsyscodeid", searchPrepayInfo.getSellsyscodeid());
        result.put("sellorganid", searchPrepayInfo.getSellorganid());
        String sql = "buysyscodeid = #{syscodeid} and buyorganid = #{organid} and sellsyscodeid = #{sellsyscodeid} and sellorganid = #{sellorganid}";
        AccountPrepay accountPrepay = accountPrepayService.selectOneByWhr0(sql, result);
        return accountPrepay != null;
    }

    @Override
    public Map<String, String> searchPrepayBalanceForCld(UpdatePrepay updatePrepay) {
        // 获取买卖家的syscodeid
        Map<String, Object> basePara = new HashMap<>();
        basePara.put("sellsyscode", updatePrepay.getSellSyscode());
        basePara.put("buysyscode", updatePrepay.getBuySyscode());
        BaseCode sellCode = baseCodeService.selectOneByWhr0("syscode = #{sellsyscode}", basePara);
        BaseCode buyCode = baseCodeService.selectOneByWhr0("syscode = #{buysyscode}", basePara);
        if (null == sellCode) {
            throw new DataNotFindException("卖家");
        }
        if (null == buyCode) {
            throw new DataNotFindException("买家");
        }
        String accountSql = " syscodeid = #{syscodeid} and matchid = #{matchid} ";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", buyCode.getId());
        para.put("matchid", updatePrepay.getBuymatchid());
        Account account = accountService.selectOneByWhr0(accountSql, para);
        // 如果没有账户就创建账户
        if (null == account) {
//            throw new DataNotFindException("买家账户");
            throw new SearchPrepayException("余额不足！");
        }
        String prepaySql = " accountid = #{accountid} and sellsyscodeid = #{sellsyscodeid} and sellmatchid = #{sellmatchid} "
                + "and buysyscodeid = #{buysyscodeid} and buymatchid = #{buymatchid}";
        para.put("accountid", account.getId());
        para.put("sellsyscodeid", sellCode.getId());
        para.put("sellmatchid", updatePrepay.getSellmatchid());
        para.put("buysyscodeid", buyCode.getId());
        para.put("buymatchid", updatePrepay.getBuymatchid());
        AccountPrepay accountPrepay = accountPrepayService.selectOneByWhr0(prepaySql, para);
        Map<String, String> data = new HashMap<>();
        if (null == accountPrepay) {
            data.put("balance", "0");
        } else {
            data.put("balance", accountPrepay.getBalance().toString());
        }
        LOGGER_PREPAYSEARCHBIZIMPL.info("云供应链查询预付货款余额，买家注册号={},卖家注册号={}", updatePrepay.getBuySyscode(), updatePrepay.getSellSyscode());
        return data;
    }
}
